package sync;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * synchronized 关键字的使用示例
 * 
 * 本类展示了synchronized关键字的多种用法：
 * 1. 同步实例方法 - 锁定当前对象实例
 * 2. 同步静态方法 - 锁定类对象
 * 3. 同步代码块(this) - 锁定当前对象实例
 * 4. 同步代码块(对象) - 锁定指定对象
 * 5. 同步代码块(类) - 锁定类对象
 * 6. 可重入性 - 展示锁的可重入特性
 * 7. 死锁示例 - 展示如何避免死锁
 */
public class Sync {
    // 共享资源
    private int count = 0;
    private static int staticCount = 0;
    private final Object lock1 = new Object();
    private final Object lock2 = new Object();
    private final List<String> list = new ArrayList<>();
    
    /**
     * 1. 同步实例方法
     * 锁定的是当前对象实例(this)
     */
    public synchronized void incrementCount() {
        count++;
        System.out.println(Thread.currentThread().getName() + " - 实例方法同步: " + count);
        try {
            // 模拟耗时操作
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 2. 同步静态方法
     * 锁定的是类对象(Sync.class)
     */
    public static synchronized void incrementStaticCount() {
        staticCount++;
        System.out.println(Thread.currentThread().getName() + " - 静态方法同步: " + staticCount);
        try {
            // 模拟耗时操作
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 3. 同步代码块(this)
     * 锁定的是当前对象实例
     */
    public void addToListSyncThis(String item) {
        // 只同步添加操作，其他操作不受影响
        synchronized(this) {
            System.out.println(Thread.currentThread().getName() + " - 同步代码块(this)开始");
            list.add(item);
            System.out.println(Thread.currentThread().getName() + " - 添加项: " + item);
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " - 同步代码块(this)结束");
        }
        
        // 这部分代码不在同步块内，不受锁保护
        System.out.println(Thread.currentThread().getName() + " - 非同步代码执行");
    }
    
    /**
     * 4. 同步代码块(对象)
     * 锁定的是指定对象lock1
     */
    public void addToListSyncObject(String item) {
        // 使用指定对象作为锁
        synchronized(lock1) {
            System.out.println(Thread.currentThread().getName() + " - 同步代码块(对象)开始");
            list.add(item);
            System.out.println(Thread.currentThread().getName() + " - 添加项: " + item);
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " - 同步代码块(对象)结束");
        }
    }
    
    /**
     * 5. 同步代码块(类)
     * 锁定的是类对象Sync.class
     */
    public void addToListSyncClass(String item) {
        // 使用类对象作为锁
        synchronized(Sync.class) {
            System.out.println(Thread.currentThread().getName() + " - 同步代码块(类)开始");
            list.add(item);
            System.out.println(Thread.currentThread().getName() + " - 添加项: " + item);
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " - 同步代码块(类)结束");
        }
    }
    
    /**
     * 6. 可重入性示例
     * 展示同一线程可以重复获取同一把锁
     */
    public synchronized void outer() {
        System.out.println(Thread.currentThread().getName() + " - 进入outer方法");
        // 同一线程在持有锁的情况下，可以再次获取同一把锁
        inner();
    }
    
    public synchronized void inner() {
        System.out.println(Thread.currentThread().getName() + " - 进入inner方法");
    }
    
    /**
     * 7. 死锁示例 - 不良实践
     */
    public void deadlockDemo1() {
        new Thread(() -> {
            synchronized(lock1) {
                System.out.println("线程1获取了lock1");
                try {
                    Thread.sleep(100); // 确保另一个线程有机会获取lock2
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                System.out.println("线程1等待获取lock2");
                synchronized(lock2) {
                    System.out.println("线程1获取了lock2"); // 这行代码可能永远不会执行
                }
            }
        }, "DeadlockThread-1").start();
        
        new Thread(() -> {
            synchronized(lock2) {
                System.out.println("线程2获取了lock2");
                try {
                    Thread.sleep(100); // 确保另一个线程有机会获取lock1
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                System.out.println("线程2等待获取lock1");
                synchronized(lock1) {
                    System.out.println("线程2获取了lock1"); // 这行代码可能永远不会执行
                }
            }
        }, "DeadlockThread-2").start();
    }
    
    /**
     * 避免死锁的示例 - 良好实践
     * 始终按照相同的顺序获取锁
     */
    public void avoidDeadlock() {
        new Thread(() -> {
            // 两个线程都按照相同顺序获取锁：先lock1后lock2
            synchronized(lock1) {
                System.out.println("线程1获取了lock1");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                synchronized(lock2) {
                    System.out.println("线程1获取了lock2");
                }
            }
        }, "SafeThread-1").start();
        
        new Thread(() -> {
            // 按相同顺序获取锁，避免死锁
            synchronized(lock1) {
                System.out.println("线程2获取了lock1");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                synchronized(lock2) {
                    System.out.println("线程2获取了lock2");
                }
            }
        }, "SafeThread-2").start();
    }
    
    /**
     * 8. 细粒度锁示例 - 良好实践
     * 不同的操作使用不同的锁，提高并发性
     */
    public void finegrainedLock() {
        new Thread(() -> {
            // 使用lock1保护操作1
            synchronized(lock1) {
                System.out.println(Thread.currentThread().getName() + " 执行操作1");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "FineGrained-1").start();
        
        new Thread(() -> {
            // 使用lock2保护操作2，可以与操作1并行执行
            synchronized(lock2) {
                System.out.println(Thread.currentThread().getName() + " 执行操作2");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "FineGrained-2").start();
    }
    
    /**
     * 9. 展示不同类型的锁之间的关系
     */
    public void demonstrateLockRelationships() {
        // 创建两个实例
        Sync instance1 = new Sync();
        Sync instance2 = new Sync();
        
        // 测试实例方法锁
        new Thread(() -> {
            instance1.incrementCount(); // 锁定instance1
        }, "InstanceLock-1").start();
        
        new Thread(() -> {
            instance2.incrementCount(); // 锁定instance2，与instance1不冲突
        }, "InstanceLock-2").start();
        
        // 测试静态方法锁
        new Thread(() -> {
            Sync.incrementStaticCount(); // 锁定Sync.class
        }, "StaticLock-1").start();
        
        new Thread(() -> {
            Sync.incrementStaticCount(); // 锁定Sync.class，与前一个线程冲突
        }, "StaticLock-2").start();
        
        // 测试类锁和实例锁的关系
        new Thread(() -> {
            instance1.incrementCount(); // 锁定instance1
        }, "MixedLock-1").start();
        
        new Thread(() -> {
            Sync.incrementStaticCount(); // 锁定Sync.class，与instance1不冲突
        }, "MixedLock-2").start();
    }
    
    /**
     * 10. synchronized性能考虑
     */
    public void performanceConsiderations() {
        final int iterations = 1000000;
        
        // 1. 测试无锁情况
        long start = System.nanoTime();
        for (int i = 0; i < iterations; i++) {
            // 无锁操作
            int temp = count;
            count = temp + 1;
        }
        long end = System.nanoTime();
        System.out.println("无锁操作耗时: " + (end - start) / 1000000.0 + " ms");
        
        // 2. 测试同步方法
        start = System.nanoTime();
        for (int i = 0; i < iterations; i++) {
            incrementCount();
        }
        end = System.nanoTime();
        System.out.println("同步方法耗时: " + (end - start) / 1000000.0 + " ms");
        
        // 3. 测试同步代码块
        start = System.nanoTime();
        for (int i = 0; i < iterations; i++) {
            synchronized(this) {
                count++;
            }
        }
        end = System.nanoTime();
        System.out.println("同步代码块耗时: " + (end - start) / 1000000.0 + " ms");
    }
    
    public static void main(String[] args) {
        Sync sync = new Sync();
        
        System.out.println("===== 1. 同步实例方法示例 =====");
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                sync.incrementCount();
            }, "Thread-" + i).start();
        }
        
        sleep(1);
        System.out.println("\n===== 2. 同步静态方法示例 =====");
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                Sync.incrementStaticCount();
            }, "Thread-" + i).start();
        }
        
        sleep(1);
        System.out.println("\n===== 3. 同步代码块(this)示例 =====");
        for (int i = 0; i < 3; i++) {
            final int index = i;
            new Thread(() -> {
                sync.addToListSyncThis("Item-" + index);
            }, "Thread-" + i).start();
        }
        
        sleep(1);
        System.out.println("\n===== 4. 同步代码块(对象)示例 =====");
        for (int i = 0; i < 3; i++) {
            final int index = i;
            new Thread(() -> {
                sync.addToListSyncObject("Item-" + index);
            }, "Thread-" + i).start();
        }
        
        sleep(1);
        System.out.println("\n===== 5. 同步代码块(类)示例 =====");
        for (int i = 0; i < 3; i++) {
            final int index = i;
            new Thread(() -> {
                sync.addToListSyncClass("Item-" + index);
            }, "Thread-" + i).start();
        }
        
        sleep(1);
        System.out.println("\n===== 6. 可重入性示例 =====");
        new Thread(() -> {
            sync.outer();
        }, "ReentrantThread").start();
        
        sleep(1);
        System.out.println("\n===== 7. 死锁示例与避免 =====");
        // 注意：取消下面的注释将导致程序死锁
        // sync.deadlockDemo1();
        
        // 使用安全的方式避免死锁
        sync.avoidDeadlock();
        
        sleep(1);
        System.out.println("\n===== 8. 细粒度锁示例 =====");
        sync.finegrainedLock();
        
        sleep(1);
        System.out.println("\n===== 9. 锁关系示例 =====");
        sync.demonstrateLockRelationships();
        
        sleep(2);
        System.out.println("\n===== 10. 性能考虑 =====");
        sync.performanceConsiderations();
    }
    
    private static void sleep(int seconds) {
        try {
            TimeUnit.SECONDS.sleep(seconds);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
